/*	Interactive Gravitational Simulator
	Project: IGS Core
	File: Simulator.h
	Author: Mike Bantegui <mbante2@gmail.com>, Hofstra University 
	Copyright (C) 2012 - 2013 Mike Bantegui

	This file is part of the IGS software package for simulating
	the N-Body problem in real-time. This was developed as part
	of a departmental honors thesis project at Hofstra University
	in the Spring 2012 semester.

	IGS is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	IGS is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef IGS_SIMULATOR_H
#define IGS_SIMULATOR_H

#include "IntegratorBase.h"
#include <limits>

namespace IGS
{

enum SteppingScheme
{
	StepConstant,
	StepShared,
	StepIndividual
};

const double MinStepSize = std::numeric_limits<double>::epsilon();
const double MaxStepSize = 1.0 / 16.0;

class Tree;

// Represents a simulator for stepping an N-Body System forward in time
class Simulator
{
private:
	// The NBodySystem that's simulating
	std::shared_ptr<NBodySystem> System;
	// The Integrator used to integrate the equations of motion
	std::shared_ptr<Integrator> Stepper;
	// The current time
	double _Time;
	// The next time
	double _NextTime;
	// The time to evaluate forces
	double _EvaluateTime;
	// The number of steps taken on last integration
	int _Steps;
	// The total steps taken
	int _TotalSteps;
	// The type of stepping scheme to use
	SteppingScheme Scheme;
	// The tree used for force evaluation
	std::shared_ptr<Tree> Accelerator;
	
	void Initialize();
	void Reset();
	void Evaluate();
	void BeginStep(const double target);
	void EndStep();

	double MinTime();

public:
	Simulator(NBodySystem *system, Integrator *stepper);
	Simulator(NBodySystem *system, Integrator *stepper, SteppingScheme scheme, Tree *tree);

	void Evolve(const double dt);
	
	std::shared_ptr<NBodySystem> GetSystem();
	std::shared_ptr<Tree> GetAccelerator();
	double EvaluateTime() const;
	double Time() const;
	int Steps() const;
	int TotalSteps() const;
};

}

#endif